package logic

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/go-resty/resty/v2"
	"github.com/gogap/logs"
	"github.com/spf13/viper"
	"math"
	"strconv"
	"sync"
	"time"
	"yundian/internel/app/dao"
	"yundian/internel/app/helper/request"
	"yundian/internel/app/models/placemodel"
	"yundian/internel/pkg/onlinesig"
	"yundian/internel/pkg/utils"
)

type GppResults struct {
	ConsignmentResults []struct {
		FailReason              string `json:"failReason"`
		OriginalConsignmentCode string `json:"originalConsignmentCode"`
		Result                  string `json:"result"`
	} `json:"consignmentResults"`
	Message string      `json:"message"`
	Result  interface{} `json:"result"`
}

var GppSendInfo sync.Map

// GPPConsignmentCreation 配送单创建接口 统一类型
func (task *TaskLogic) GPPConsignmentCreation(param *request.SendPlacePushDataReq) error {
	dbList := dao.NewStatisticalDao().GetPlaceWaitPushDataList(param).Unwrap().([]*placemodel.GppPlaceSettlementDb)
	var targetList []*placemodel.GppPlaceSettlementDb
	var maxLen = 30

	for index, item := range dbList {
		targetList = append(targetList, item)
		if len(targetList) >= maxLen || len(dbList) == index+1 {
			if err := task.GPPConsignmentCreationBatch(param, targetList); err != nil {
				logs.Error("GPPConsignmentCreationBatch", err)
			}
			targetList = []*placemodel.GppPlaceSettlementDb{}
		}
	}

	return nil
}

// GPPConsignmentCreationBatch 配送单创建接口 分批推送
func (task *TaskLogic) GPPConsignmentCreationBatch(param *request.SendPlacePushDataReq, dbList []*placemodel.GppPlaceSettlementDb) error {
	url := viper.GetString("gpp.url")
	account := viper.GetString("gpp.account")
	password := viper.GetString("gpp.password")
	vendor := viper.GetString("gpp.vendor")
	product := viper.GetString("gpp.product")
	taxRate := 0.06

	if url == "" || account == "" || password == "" {
		return errors.New("account config error")
	}

	postDataList := []interface{}{}
	headerData := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Basic " + onlinesig.Base64(fmt.Sprintf("%s:%s", account, password)),
	}

	if _, ok := GppSendInfo.Load("send_progress"); ok {
		return errors.New("推送中未完成，请稍后")
	}

	GppSendInfo.Store("send_progress", true)
	var settlementAllOrders []string
	var settlementFailOrders []string
	var settlementSuccessOrders []string
	//dbList := dao.NewStatisticalDao().GetPlaceWaitPushDataList(param).Unwrap().([]*placemodel.GppPlaceSettlementDb)
	for _, item := range dbList {
		if item.SettlementMoney == 0 {
			continue
		}

		settlementAllOrders = append(settlementAllOrders, item.OriginalOrder)
		settlementMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(item.SettlementMoney)/100), 2)
		preTaxBasePrice, _ := strconv.ParseFloat(fmt.Sprintf("%.10f", taxRateFn(taxRate, settlementMoney)/float64(item.OrderCount)), 10)
		//proportion, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(item.Proportion)/100), 2)
		proportionFee := getProportionFee(item)
		monthBegin := fmt.Sprintf(`%s-01 00:00:00`, item.Month)
		t, _ := time.Parse("2006-01-02 15:04:05", monthBegin)
		monthEnd := utils.AddDate(t, 0, 1).Format("2006-01-02 15:04:05")
		postData := map[string]interface{}{
			"orderCode":               "",
			"originalOrderCode":       "",
			"originalConsignmentCode": item.OriginalOrder,
			"type":                    "1",
			"customerUnitCode":        "PHGC" + item.HotelId,
			"status":                  "DELIVERED",
			"deliveryDate":            monthBegin,
			"shipDate":                monthEnd,
			"receiver":                "ZM",
			"preTaxTotalPrice":        taxRateFn(taxRate, settlementMoney),
			"totalPrice":              settlementMoney,
			"memo":                    "ZM结算推送",
			"orderCreateDate":         monthBegin,
			"orderPhase":              "OPERATING",
		}
		entries := []map[string]interface{}{}
		entries = append(entries, map[string]interface{}{
			"originalConsignmentRowCode": fmt.Sprintf("%s_0", item.OriginalOrder),
			"originalRowNo":              "",
			"productCode":                product,
			"productCodeType":            "1",
			"contractOwner":              "GPP",
			"vendorCode":                 vendor,
			"preTaxBasePrice":            math.Abs(preTaxBasePrice),
			"preTaxSubtotal":             taxRateFn(taxRate, settlementMoney),
			"preTaxTotalPrice":           taxRateFn(taxRate, settlementMoney),
			"subtotal":                   settlementMoney,
			"totalPrice":                 settlementMoney,
			"amount":                     fmt.Sprintf("%d", item.OrderCount),
			"taxRate":                    taxRate,
			"commission":                 proportionFee,
		})
		postData["entries"] = entries
		postDataList = append(postDataList, postData)
	}

	if len(postDataList) == 0 {
		GppSendInfo.Delete("send_progress")
		return nil
	}

	mjson, _ := json.Marshal(postDataList)
	fmt.Println("=====================")
	fmt.Println(string(mjson))
	fmt.Println("=====================")
	fmt.Println(headerData)

	client := resty.New()
	resp, err := client.R().SetBody(postDataList).SetHeaders(headerData).Post(url)
	GppSendInfo.Delete("send_progress")
	if err != nil {
		fmt.Println("GPPConsignmentCreation-post", err)
		return err
	}

	var gppResultsData *GppResults
	json.Unmarshal([]byte(string(resp.Body())), &gppResultsData)
	fmt.Println(string(resp.Body()))

	// 更新状态
	if gppResultsData.Result == 1 {
		if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusSuccess(settlementAllOrders); uData.Err != nil {
			fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-All", uData.Err)
		}
		return err
	} else if len(gppResultsData.ConsignmentResults) == 0 {
		if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusFail(settlementAllOrders); uData.Err != nil {
			fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-All", uData.Err)
		}
		return err
	}

	for _, item := range gppResultsData.ConsignmentResults {
		if item.Result == "fail" {
			settlementFailOrders = append(settlementFailOrders, item.OriginalConsignmentCode)
		} else {
			settlementSuccessOrders = append(settlementSuccessOrders, item.OriginalConsignmentCode)
		}
	}
	if len(settlementSuccessOrders) > 0 {
		if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusSuccess(settlementSuccessOrders); uData.Err != nil {
			fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-Success", uData.Err)
		}
	}
	if len(settlementFailOrders) > 0 {
		if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusFail(settlementFailOrders); uData.Err != nil {
			fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusFail-Fail", uData.Err)
		}
	}

	return err
}

// 中曼内部执行
func (task *TaskLogic) GPPConsignmentCreationByZm(param *request.SendPlacePushDataReq) error {
	//dbList := dao.NewStatisticalDao().GetPlaceWaitPushDataListByZm(param).Unwrap().([]*placemodel.GppPlaceSettlementDb)
	dbList := dao.NewStatisticalDao().GetPlaceWaitPushDataList(param).Unwrap().([]*placemodel.GppPlaceSettlementDb)
	//var targetList []*placemodel.GppPlaceSettlementDb
	//var maxLen = 300

	var totalSettlement, allSettlement, totalPlatServe float64
	postDataList := []interface{}{}
	for _, item := range dbList {
		if item.SettlementMoney == 0 {
			continue
		}

		proportionFee := getProportionFee(item)
		totalSettlement = totalSettlement + proportionFee
		allSettlement += float64(item.SettlementMoney)

		postDataList = append(postDataList, map[string]interface{}{
			"place_id":         item.PlaceId,
			"hotel_id":         item.HotelId,
			"settlement_money": float64(item.SettlementMoney) / 100,
			"commission":       proportionFee,
		})

		//serveFeeAmount := float64(item.SettlementMoney) * 2 / 100
		//totalPlatServe = totalPlatServe + serveFeeAmount
		//targetList = append(targetList, item)
		//if len(targetList) >= maxLen || len(dbList) == index+1 {
		//	s, p, _ := task.GPPConsignmentCreationBatchByZm(param, targetList)
		//	//if err := task.GPPConsignmentCreationBatchByZm(param, targetList); err != nil {
		//	//	logs.Error("GPPConsignmentCreationBatch", err)
		//	//}
		//	totalSettlement = totalSettlement + s
		//	totalPlatServe = totalPlatServe + p
		//	targetList = []*placemodel.GppPlaceSettlementDb{}
		//}
	}
	mjson, _ := json.Marshal(postDataList)
	fmt.Println("=====================")
	fmt.Println(string(mjson))
	fmt.Println("=====================")

	logs.Info("================================")
	logs.Info(totalSettlement, int(allSettlement), totalPlatServe)
	logs.Info("================================")
	time.Sleep(time.Second * 10)
	return nil
}

func (task *TaskLogic) GPPConsignmentCreationBatchByZm(param *request.SendPlacePushDataReq, dbList []*placemodel.GppPlaceSettlementDb) (settlement, platServe float64, err error) {
	url := viper.GetString("gpp.url")
	account := viper.GetString("gpp.account")
	password := viper.GetString("gpp.password")
	vendor := viper.GetString("gpp.vendor")
	product := viper.GetString("gpp.product")
	taxRate := 0.06

	if url == "" || account == "" || password == "" {
		return 0.00, 0.00, errors.New("account config error")
	}

	postDataList := []interface{}{}
	//headerData := map[string]string{
	//	"Content-Type":  "application/json",
	//	"Authorization": "Basic " + onlinesig.Base64(fmt.Sprintf("%s:%s", account, password)),
	//}

	if _, ok := GppSendInfo.Load("send_progress"); ok {
		return 0.00, 0.00, errors.New("推送中未完成，请稍后")
	}

	GppSendInfo.Store("send_progress", true)
	var settlementAllOrders []string
	//var settlementFailOrders []string
	//var settlementSuccessOrders []string
	//dbList := dao.NewStatisticalDao().GetPlaceWaitPushDataList(param).Unwrap().([]*placemodel.GppPlaceSettlementDb)
	var totalSettlement, totalPlatServe float64
	for _, item := range dbList {
		if item.SettlementMoney == 0 {
			continue
		}

		settlementAllOrders = append(settlementAllOrders, item.OriginalOrder)
		settlementMoney, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(item.SettlementMoney)/100), 2)
		preTaxBasePrice, _ := strconv.ParseFloat(fmt.Sprintf("%.10f", taxRateFn(taxRate, settlementMoney)/float64(item.OrderCount)), 10)
		//proportion, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(item.Proportion)/100), 2)
		proportionFee := getProportionFee(item)
		totalSettlement = totalSettlement + proportionFee
		serveFeeAmount := float64(item.SettlementMoney) * 2 / 100
		totalPlatServe = totalPlatServe + serveFeeAmount
		monthBegin := fmt.Sprintf(`%s-01 00:00:00`, item.Month)
		t, _ := time.Parse("2006-01-02 15:04:05", monthBegin)
		monthEnd := utils.AddDate(t, 0, 1).Format("2006-01-02 15:04:05")
		postData := map[string]interface{}{
			"orderCode":               "",
			"originalOrderCode":       "",
			"originalConsignmentCode": item.OriginalOrder,
			"type":                    "1",
			"customerUnitCode":        "PHGC" + item.HotelId,
			"status":                  "DELIVERED",
			"deliveryDate":            monthBegin,
			"shipDate":                monthEnd,
			"receiver":                "ZM",
			"preTaxTotalPrice":        taxRateFn(taxRate, settlementMoney),
			"totalPrice":              settlementMoney,
			"memo":                    "ZM结算推送",
			"orderCreateDate":         monthBegin,
			"orderPhase":              "OPERATING",
		}
		entries := []map[string]interface{}{}
		entries = append(entries, map[string]interface{}{
			"originalConsignmentRowCode": fmt.Sprintf("%s_0", item.OriginalOrder),
			"originalRowNo":              "",
			"productCode":                product,
			"productCodeType":            "1",
			"contractOwner":              "GPP",
			"vendorCode":                 vendor,
			"preTaxBasePrice":            preTaxBasePrice,
			"preTaxSubtotal":             taxRateFn(taxRate, settlementMoney),
			"preTaxTotalPrice":           taxRateFn(taxRate, settlementMoney),
			"subtotal":                   settlementMoney,
			"totalPrice":                 settlementMoney,
			"amount":                     fmt.Sprintf("%d", item.OrderCount),
			"taxRate":                    taxRate,
			"commission":                 proportionFee,
		})
		postData["entries"] = entries
		postDataList = append(postDataList, postData)
	}

	if len(postDataList) == 0 {
		GppSendInfo.Delete("send_progress")
		return 0.00, 0.00, nil
	}

	//mjson, _ := json.Marshal(postDataList)
	//fmt.Println("=====================")
	//fmt.Println(string(mjson))
	//fmt.Println("=====================")
	//fmt.Println(headerData)

	//client := resty.New()
	//resp, err := client.R().SetBody(postDataList).SetHeaders(headerData).Post(url)
	//GppSendInfo.Delete("send_progress")
	//if err != nil {
	//	fmt.Println("GPPConsignmentCreation-post", err)
	//	return err
	//}

	//var gppResultsData *GppResults
	//json.Unmarshal([]byte(string(resp.Body())), &gppResultsData)
	//fmt.Println(string(resp.Body()))
	//
	//// 更新状态
	//if gppResultsData.Result == 1 {
	//	if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusSuccess(settlementAllOrders); uData.Err != nil {
	//		fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-All", uData.Err)
	//	}
	//	return err
	//} else if len(gppResultsData.ConsignmentResults) == 0 {
	//	if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusFail(settlementAllOrders); uData.Err != nil {
	//		fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-All", uData.Err)
	//	}
	//	return err
	//}

	//for _, item := range gppResultsData.ConsignmentResults {
	//	if item.Result == "fail" {
	//		settlementFailOrders = append(settlementFailOrders, item.OriginalConsignmentCode)
	//	} else {
	//		settlementSuccessOrders = append(settlementSuccessOrders, item.OriginalConsignmentCode)
	//	}
	//}
	//if len(settlementSuccessOrders) > 0 {
	//	if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusSuccess(settlementSuccessOrders); uData.Err != nil {
	//		fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusSuccess-Success", uData.Err)
	//	}
	//}
	//if len(settlementFailOrders) > 0 {
	//	if uData := dao.NewStatisticalDao().SetPlacePushDataListStatusFail(settlementFailOrders); uData.Err != nil {
	//		fmt.Println("GPPConsignmentCreation-SetPlacePushDataListStatusFail-Fail", uData.Err)
	//	}
	//}

	//return err
	return totalSettlement, totalPlatServe, nil
}

func taxRateFn(taxRate, val float64) float64 {
	if val == 0 || taxRate == 0 {
		return val
	}
	val, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", val/(1+taxRate)), 2)
	return val
}

//func getProportionFee(item *placemodel.GppPlaceSettlementDb) float64 {
//	if item.Commission > 0 {
//		return item.Commission
//	}
//
//	// 服务费
//	serveFeeAmount := float64(item.SettlementMoney) * 2 / 100
//	targetSettlementMoney := math.Abs(float64(item.SettlementMoney))
//	proportionFee := (targetSettlementMoney - serveFeeAmount) * 8 / 100
//
//	return proportionFee
//}

func getProportionFee(item *placemodel.GppPlaceSettlementDb) float64 {
	if item.Commission > 0 {
		return item.Commission
	}

	// 服务费
	serveFeeAmount := float64(item.SettlementMoney) * 2 / 100
	//serveFeeAmount := float64(0)

	targetSettlementMoney := math.Abs(float64(item.SettlementMoney))
	targetCostAmount := math.Abs(float64(item.CostAmount))

	proportionFee := 0.00
	if targetSettlementMoney == 0 {
		proportionFee = 0.00
	} else if targetSettlementMoney <= targetCostAmount {
		proportionFee, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", (serveFeeAmount+float64(item.CostAmount))/100), 2)
	} else if targetSettlementMoney > targetCostAmount {
		num := serveFeeAmount + float64(item.CostAmount) + float64(item.SettlementMoney-item.CostAmount)*item.Proportion/100
		proportionFee, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", num/100), 2)
	}

	return proportionFee
}

func (task *TaskLogic) GPPConsignmentCreationTest() {
	url := viper.GetString("gpp.url")
	account := viper.GetString("gpp.account")
	password := viper.GetString("gpp.password")

	headerData := map[string]string{
		"Content-Type":  "application/json",
		"Authorization": "Basic " + onlinesig.Base64(fmt.Sprintf("%s:%s", account, password)),
	}
	postData := map[string]interface{}{
		"originalConsignmentCode": "ZM20210607160641457651",
		"type":                    "1",
		"customerUnitCode":        "758",
		"status":                  "DELIVERED",
		"deliveryDate":            "2022-07-01 00:00:00",
		"shipDate":                "2022-08-01 00:00:00",
		"preTaxTotalPrice":        800.00,
		"totalPrice":              1000.00,
	}
	entries := []map[string]interface{}{}
	entries = append(entries, map[string]interface{}{
		"productCode":      "31895",
		"productCodeType":  "3",
		"vendorCode":       "",
		"preTaxBasePrice":  800.00,
		"preTaxSubtotal":   800.00,
		"preTaxTotalPrice": 800.00,
		"subtotal":         1000.00,
		"totalPrice":       1000.00,
		"amount":           "100",
		"taxRate":          0.2,
		"commission":       248 + (1000.00-248)*0.8,
	})
	postData["entries"] = entries
	postDataList := []interface{}{postData}

	mjson, _ := json.Marshal(postData)
	fmt.Println(string(mjson))
	fmt.Println(headerData)
	client := resty.New()
	resp, err := client.R().SetBody(postDataList).SetHeaders(headerData).Post(url)
	if err != nil {
		logs.Error("GPPConsignmentCreation-post", err)
		return
	}

	infoData := map[string]interface{}{}
	json.Unmarshal([]byte(string(resp.Body())), &infoData)
	fmt.Println(string(resp.Body()))
	//logs.Info(infoData)
}
